#!/usr/bin/python3
#!coding:utf-8
import os
import sys
import time
import threading
import rospy
import pyaudio
from std_msgs.msg import String
from pi_ai.audio_recognizer import AudioRecognizer
from pi_ai.speech_synthesizer3 import SpeechSynthesizer
from pi_driver.srv import GetString, GetStringResponse, SetString, SetStringResponse

sys.path.append(os.path.expanduser('~') + '/Lepi_Data/ros/smart_audio_node')
if True:
    import snowboydecoder

default_params = {
    'alexa.umdl': (0.6, True),
    'snowboy.umdl': (0.5, False),
    'jarvis.umdl': ([0.8, 0.8], True),
    'smart_mirror.umdl': (0.5, False),
    'subex.umdl': (0.5, True),
    'neoya.umdl': ([0.7, 0.7], True),
    'hey_extreme.umdl': (0.6, True),
    'computer.umdl': (0.6, True),
    'view_glass.umdl': (0.7, True),
}
tts_dir = os.path.expanduser('~') + '/Lepi_Data/Music'


class SmartAudioNode(object):

    def __init__(self):
        self.node_name = rospy.get_name()
        rospy.loginfo("[%s] Initializing......" % (self.node_name))
        self.list_audio_devices()
        self.asr_model = AudioRecognizer()
        self.tts_model = SpeechSynthesizer()

        self.model_dir = os.path.expanduser(
            '~') + '/Lepi_Data/ros/smart_audio_node/resources/models/'
        # self.pub_detections = rospy.Publisher("~image_text", CompressedImage, queue_size=1)
        self.hotwordDetect = False
        self.tts_busy = False
        self.asr_busy = False
        keyword_model = self.model_dir + 'snowboy.umdl'
        self.detector = snowboydecoder.HotwordDetector(keyword_model,
                                                       sensitivity=0.5)
        self.pubHotwordDetect = rospy.Publisher('~hotword_detect',
                                                String,
                                                queue_size=1)
        rospy.Service('~toggle_hotword_detect', SetString,
                      self.cbToggleHotwordDetect)
        rospy.Service('~switch_hotword_model', SetString,
                      self.cbSwitchHotwordModel)
        rospy.Service('~tts_offline', GetString, self.cbTTSOffline)
        rospy.Service('~detect_command', GetString, self.cbDetectCommand)
        rospy.Service('~stop_speak', SetString, self.cbStopSpeak)

        reader = threading.Thread(target=self.startHotwordDetect)
        # reader.daemon = True
        reader.start()
        rospy.loginfo("[%s] Initialized." % (self.node_name))

    def list_audio_devices(self):
        p = pyaudio.PyAudio()
        device_count = p.get_device_count()
        for i in range(0, device_count):
            info = p.get_device_info_by_index(i)
            # print("Device {} = {}".format(info["index"], info["name"]))
            if 'wm8960' in info["name"]:
                self.input_device_index = info["index"]
                print("Device {} = {}".format(info["index"], info["name"]))
                print((i,info['maxInputChannels'],info['maxOutputChannels']))
                if info['maxOutputChannels'] > 0:
                    break
                else:
                    os.system("curl http://localhost:8000/rosNode/launch?name=/ubiquityrobot/smart_audio_node&force=true")
                    time.sleep(60)
                    sys.exit()

    def cbTTSOffline(self, params):
        data = params.data
        if len(data) == 0:
            return GetStringResponse("没有合成文本")
        if self.tts_busy == True:
            return GetStringResponse("请等待上一条语音朗读完成")
        self.tts_busy = True
        try:
            if data[-1] != '。':
                out_path = os.path.join(tts_dir, data + '.wav')
                data = data + '。'
            else:
                out_path = os.path.join(tts_dir, data[:-1] + '.wav')
            self.tts_model.out_path = out_path
            self.tts_model.tts(data)
            # cmd = 'aplay "%s"' % os.path.join(out_path)
            # os.system(cmd)
            # self.tts_model.play(out_path)
        except Exception as e:
            print(e)
        self.tts_busy = False
        return GetStringResponse(data)

    def cbDetectCommand(self, params):
        text = ''
        if self.asr_busy == True:
            time.sleep(0.2)
            return GetStringResponse("请等待上一条语音识别完成")
        self.asr_busy = True
        try:
            text = self.asr_model.recognize()
            text = text.replace(' ', '')
        except Exception as e:
            print(e)
        print(params, text)
        self.asr_busy = False
        return GetStringResponse(text)

    def cbToggleHotwordDetect(self, params):
        if params.data == 'open':
            if self.detector._running:
                return SetStringResponse('正在运行')
            else:
                self.hotwordDetect = True
                while not self.detector._running:
                    time.sleep(0.03)
                return SetStringResponse('已启动')

        elif params.data == 'close':
            self.asr_model.detecting = False
            # print(self.asr_model.detecting)
            if self.detector._running:
                # self.detector.terminate()
                self.hotwordDetect = False
                while self.detector._running:
                    time.sleep(0.03)
                return SetStringResponse('已停止')
            else:
                return SetStringResponse('没有运行')
        else:
            print(params.data)
            return SetStringResponse(params.data)

    def startHotwordDetect(self):
        while True:
            if self.hotwordDetect:
                print('starting')
                try:
                    self.detector.start(
                        detected_callback=self.cbPublishHotwordDetect,
                        interrupt_check=self.interrupt_check,
                        sleep_time=0.03)
                except Exception as e:
                    print(e)
                    time.sleep(0.5)
            else:
                if self.detector._running:
                    self.detector.terminate()
                    print('terminated')
            time.sleep(0.1)

    def interrupt_check(self):
        return self.hotwordDetect == False

    def cbPublishHotwordDetect(self, params=None):
        # self.detector.terminate()
        print('hotword detected')
        self.pubHotwordDetect.publish(String('hotword detected'))
        # self.startHotwordDetect()

    def cbSwitchHotwordModel(self, params):
        data = params.data
        if self.detector._running:
            self.hotwordDetect = False
            while self.detector._running:
                time.sleep(0.03)
        if data in default_params.keys():
            self.detector = snowboydecoder.HotwordDetector(
                self.model_dir + data,
                sensitivity=default_params[data][0],
                apply_frontend=default_params[data][1])
        else:
            self.detector = snowboydecoder.HotwordDetector(self.model_dir +
                                                           data)
        return SetStringResponse('切换成功')

    def cbStopSpeak(self, params):
        self.tts_model.kill()
        return SetStringResponse('OK')

    def onShutdown(self):
        self.hotwordDetect = False
        rospy.loginfo("[%s] Shutdown." % (self.node_name))


if __name__ == '__main__':
    rospy.init_node('smart_audio_node', anonymous=False)
    node = SmartAudioNode()
    rospy.on_shutdown(node.onShutdown)
    rospy.spin()
